<!DOCTYPE html>
<html>
	<head>
		<title>配积载效果图</title>
		<meta charset="utf-8">
		<script src="js/vue.js"></script>
		<script src="js/commom.js"></script>
		<script src="js/jquery-3.1.1.min.js"></script>
		<!-- <script src="js/three.js"></script> -->
		<style>
			body {
				margin: 0;
				overflow: hidden;
			}

			#title {
				position: absolute;
				top: 1px;
				color: #3C6DA8;
				/* font-weight: bold; */
				font-size: 24px;
				text-align: center;
				padding: 10px 30px 10px 30px;
			}

			#btn_load {
				background-color: #3C6DA8;
				border-radius: 100px;
				width: 100px;
				line-height: 40px;
				color: white;
				font-size: 16px;
				text-align: center;
				cursor: pointer;
			}

			#btn_reset {
				background-color: #3C6DA8;
				border-radius: 100px;
				width: 100px;
				line-height: 40px;
				color: white;
				font-size: 16px;
				text-align: center;
				margin: 0 0 0 20px;
				cursor: pointer;
			}
		</style>
	</head>
	<body>

		<div id="page">
			<div id="webgl">
				<!-- 模型容器 -->
			</div>

			<!-- 			<div id="tag"
				style="width: auto;background-color: #3C6DA8;color: white;text-align: center;padding:10px 30px 10px 30px;">
				积载效果图
			</div> -->

			<div style="display: flex;width: 100%;justify-content: center;">
				<div id="title">
					配 积 载 效 果 图
				</div>
			</div>

			<div style="display: flex;width: 100%;justify-content: center;position: absolute;bottom: 12%;">
				<div id="btn_load" @click="onStartLoad">开始装车</div>
				<!-- <div id="btn_reset" @click="reset">重置</div> -->
				<div id="btn_reset" @click="importImg">导出效果图</div>
			</div>

		</div>

		<script type="importmap">
			{
			    "imports": {
			      "three": "./js/three.module.js",
			      "three/addons/": "./js/controls/"
			    }
			}
		</script>

		<script type="module">
			// import * as THREE from './js/three.module.js';

			import { rotateXZ90, getMaxSize, } from './js/my.js'

			import * as THREE from 'three';

			import { OrbitControls } from './js/controls/OrbitControls.js';
			// 引入性能监视器stats.js
			import Stats from './js/libs/stats.module.js';
			// gui
			import { GUI } from './js/libs/lil-gui.module.min.js';
			// 引入CSS2渲染器CSS2DRenderer和CSS2模型对象CSS2DObject
			import { CSS2DRenderer, CSS2DObject } from './js/renderers/CSS2DRenderer.js';
			// GLTF加载器
			import { GLTFLoader } from './js/loaders/GLTFLoader.js';
			// 后期处理 效果生成器
			import { EffectComposer } from './js/pp/postprocessing/EffectComposer.js';
			// 引入渲染器通道RenderPass
			import { RenderPass } from './js/pp/postprocessing/RenderPass.js';
			// 描边特效
			// 引入OutlinePass通道
			import { OutlinePass } from './js/pp/postprocessing/OutlinePass.js';

			var vm = new Vue({
				el: '#page',
				data() {
					return {
						demo: { a: 'i am a' },

						// 积载数据模型
						tpList: [{
							trayno: 'SHT000001', // 托盘编码
							weight: 100, // 重量
							length: 100, // 长度
							width: 100, // 宽度
							hight: 100, // 高度
							position: 'W', // E 东侧 W 西侧
							goods_sn: 'No.2401010001', // 货号
							goods_name: '货物名称01', // 货物名称
							goods_munit: '件', // 货物单位
							load_num: 1, // 货物数量
						}, ],

						// 页面进度和标题
						title: '积载效果图',

						scene: {},
						camera: {},
						renderer: {},
						stats: {},
						gui: {}, // 可视化调试组件
						loader: {}, // GLTF loader
						raycaster: {}, // 射线检测器
						mouse: {}, // 鼠标位置

						// 相机位置
						cameraX: 700,
						cameraY: 600,
						cameraZ: 400,

						// 车身尺寸
						truckX: 240,
						truckY: 20,
						truckZ: 420,
						max_high: 400, // 限高
						// 车轮半径
						wheelRad: 30,
						// 车轮厚度
						wheelD: 22,
						// 车头尺寸
						headX: 240,
						headY: 180,
						headZ: 140,
						// 原生弹窗
						hoverBox: {},

						// 车/货整体分组
						tg_group: {},
						// 车辆分组
						t_group: {},
						// 货物分组
						g_group: {},

						// gui调试对象
						debug: {
							is_rotate: false, // 是否旋转
							x: 0,
							y: 0,
							z: 0,
							is_animate: false, // 是否执行装车动画
						},

						// html标注渲染 
						css2Renderer: {},

						//纹理贴图加载器TextureLoader
						textureLoader: {},

						// 记录货物列表
						goodsMeshList: [],

						// 效果生成器
						composer: {},
						// 描边特效通道
						outlinePass: {},

						// 装车队列timeout
						timeOutList: [],
					}
				},
				mounted: function() {

					const params = new URLSearchParams(window.location.search)
					const ids = params.get('ids')
					console.log(`ids = `, ids);

					// const path = window.location.pathname
					// console.log(`path = `, path);

					if (ids) this.getJizai(ids)

					this.initScene()
					this.initGui()
					// this.createTruck()
					// this.createMesh()
					// this.createTag()
					this.createGLTFLoader()
					this.postProcessing()
					this.animate()
				},

				methods: {

					// 获取积载方案 /api/index/view?ids=3
					async getJizai(ids) {
						let res = await ajax(`${API_URL_PJZ}/api/index/view`, 'GET', { ids })
						console.log(`getJizai.res = `, res);

						try {
							this.truckZ = res.data.car.length * 100
							this.truckX = res.data.car.width * 100
							this.headX = res.data.car.width * 100
							this.max_high = res.data.car.max_high * 100

							this.createTruck()
							this.createOutline()
						} catch (e) {}

						try {
							this.tpList = res.data.info
							this.createMesh()
						} catch (e) {}

					},

					initScene() {

						// 初始化分组
						this.tg_group = new THREE.Group()
						this.t_group = new THREE.Group()
						this.g_group = new THREE.Group()

						// 贴图加载器
						this.textureLoader = new THREE.TextureLoader()

						// 场景
						this.scene = new THREE.Scene()

						// AmbientLight PointLight
						const pointLight = new THREE.PointLight(0x404040, 6.0)
						// 光源衰减
						pointLight.decay = 0.0 //设置光源不随距离衰减
						// 光源位置
						pointLight.position.set(400, 600, 600)
						this.scene.add(pointLight) //点光源添加到场景中
						// 光源2
						const light2 = new THREE.PointLight(0x404040, 3.0)
						light2.position.set(-400, 800, -400)
						// 光源3
						const light3 = new THREE.DirectionalLight(0x404040, 4.0)
						light3.position.set(300, 0, -50)
						// 光源4
						const light4 = new THREE.DirectionalLight(0x404040, 4.0)
						light4.position.set(-300, 0, -50)
						// 光源5
						const light5 = new THREE.DirectionalLight(0x404040, 4.0)
						light5.position.set(100, 0, -200)
						this.scene.add(light2, light3, light4, light5) // 将光源添加到场景中

						// 点光源辅助观察
						const lightHelper = new THREE.PointLightHelper(pointLight, 4, '#ffffff')
						this.scene.add(lightHelper)
						const lightHelper2 = new THREE.PointLightHelper(light2, 4, '#ffffff')
						this.scene.add(lightHelper2)
						const lightHelper3 = new THREE.PointLightHelper(light3, 4, '#ffffff')
						this.scene.add(lightHelper3)
						const lightHelper4 = new THREE.PointLightHelper(light4, 4, '#ffffff')
						this.scene.add(lightHelper4)

						// width和height用来设置Three.js输出的Canvas画布尺寸(像素px)
						const width = window.innerWidth //宽度
						const height = window.innerHeight //高度
						// 视场角度 width/height画布宽高比 到近裁截面距离 到远裁截面距离
						this.camera = new THREE.PerspectiveCamera(50, width / height, 1, 5000)
						// 根据需要设置相机位置具体值
						this.camera.position.set(this.cameraX, this.cameraY, this.cameraZ)
						// 相机观察目标指向Threejs 3D空间中某个位置
						this.camera.lookAt(0, 0, 0); // 坐标原点

						// 渲染器
						this.renderer = new THREE.WebGLRenderer({ antialias: true, })
						this.renderer.setSize(window.innerWidth, window.innerHeight)
						document.getElementById('webgl').appendChild(this.renderer.domElement)
						// 获取屏幕的设备像素比devicePixelRatio告诉threejs,以免渲染模糊问题
						this.renderer.setPixelRatio(window.devicePixelRatio)
						this.renderer.setClearColor('#dddddd', 1); //设置背景颜色

						// AxesHelper：辅助观察的坐标系
						const axesHelper = new THREE.AxesHelper(2000)
						// this.scene.add(axesHelper)

						// 设置相机控件轨道控制器OrbitControls
						const controls = new OrbitControls(this.camera, this.renderer.domElement)
						// 如果OrbitControls改变了相机参数，重新调用渲染器渲染三维场景
						controls.addEventListener('change', () => {
							// 开启循环渲染后,此处无需重复渲染
							// this.renderer.render(this.scene, this.camera) // 执行渲染操作

						})

						window.onresize = () => {
							// HTML标签css2Renderer.domElement尺寸重新设置
							// this.css2Renderer.setSize(innerWidth, innerHeight);
							this.renderer.setSize(innerWidth, innerHeight)
							this.camera.aspect = innerWidth / innerHeight
							this.camera.updateProjectionMatrix()
						}

						this.createDailog()

						this.scene.position.set(-80, 0, -400)

					},

					// 处理鼠标悬停事件
					showHoverBox(event) {

						const rect = this.renderer.domElement.getBoundingClientRect()
						this.mouse = new THREE.Vector2();
						this.mouse.x = (event.clientX - rect.left) / rect.width * 2 - 1
						this.mouse.y = -(event.clientY - rect.top) / rect.height * 2 + 1

						// 将鼠标位置转换为三维坐标
						this.raycaster = new THREE.Raycaster()
						this.raycaster.setFromCamera(this.mouse, this.camera)
						const intersects = this.raycaster.intersectObjects(this.goodsMeshList)

						if (intersects.length > 0) {
							let currMesh = intersects[0].object
							this.outlinePass.selectedObjects = [currMesh] // 描边一个模型对象

							let data = currMesh.userData

							// 如果鼠标悬停在物体上，显示框
							this.hoverBox.style.display = 'block'
							this.hoverBox.innerHTML =
								`
								<!-- <p style="width:100%;text-align:center;font-weight:bold">货物信息</p> -->						
								<p>
									<span>${currMesh.name}</span>
									<span>货号${data.goods_sn}</span>									
								</p>
								<span>数量 ${data.load_num} ${data.goods_munit}</span>
								<p>托盘${data.trayno}</p>
								<p>长${data.length}cm 宽${data.width}cm 高${data.hight}cm 重${data.weight}kg</p>
								`
							this.hoverBox.style.left = `${event.clientX + 24}px`
							this.hoverBox.style.top = `${event.clientY - 0}px`

						} else {
							// 如果没有悬停在物体上，隐藏框
							this.hoverBox.style.display = 'none'
							this.outlinePass.selectedObjects = [] // 取消所有模型描边
						}
					},

					// 创建悬停弹窗dom组件
					createDailog() {
						// 为物体添加鼠标悬停事件
						this.hoverBox = document.createElement('div');
						this.hoverBox.style.position = 'absolute';
						this.hoverBox.style.backgroundColor = '#3C6DA8';
						this.hoverBox.style.border = '2px solid #cccccc';
						this.hoverBox.style.color = 'white';
						this.hoverBox.style.padding = '0px 16px 0px 16px';
						this.hoverBox.style.fontSize = '12px';
						this.hoverBox.style.display = 'none'; // 默认隐藏
						this.hoverBox.style.borderRadius = '18px'; // 默认隐藏
						document.body.appendChild(this.hoverBox);
					},

					// 处理鼠标按下事件
					onDomMouseDown(event) {
						// event.preventDefault();

						// 计算鼠标在canvas中的坐标
						this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1
						this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1

						// 把鼠标坐标转换为three.js中的坐标
						this.raycaster = new THREE.Raycaster()
						this.raycaster.setFromCamera(this.mouse, this.camera)
						// 计算射线和立方体的交点
						var intersects = this.raycaster.intersectObjects(this.goodsMeshList)

						// 处理点击事件
						if (intersects.length > 0) {
							let currMesh = intersects[0].object
							this.outlinePass.selectedObjects = [currMesh] // 描边一个模型对象
							// this.outlinePass.selectedObjects = [mesh1, mesh2, group] // 描边多个模型对象
						}
					},

					// gui
					initGui() {
						this.gui = new GUI()
						// gui增加交互界面，用来改变对应属性的值
						this.gui.add(this.debug, 'is_rotate').name('是否旋转')
						// this.gui.add(this.debug, 'is_animate').name('装车动画')
						this.gui.close()
						// 添加分组菜单
						let xyzFolder = this.gui.addFolder('位置')
						xyzFolder.add(this.debug, 'x', -200, 200).name('横向位置')
						xyzFolder.add(this.debug, 'y', -200, 200).name('纵向位置')
						xyzFolder.add(this.debug, 'z', -200, 200).name('深度位置')
						xyzFolder.close()
					},

					// 创建汽车
					createTruck() {

						// 创建车辆的几何体:车身长度 宽度 高度
						const carGeometry = new THREE.BoxGeometry(this.truckX, this.truckY, this.truckZ)
						// 轮子半径 底部半径 高度 分段数
						const wheelGeometry = new THREE.CylinderGeometry(this.wheelRad, this.wheelRad, this.wheelD, 48)
						// 车头形状
						const headGeometry = new THREE.BoxGeometry(this.headX, this.headY, this.headZ)
						// 轮毂形状
						const hubGeometry = new THREE.CylinderGeometry(this.wheelRad / 2, this.wheelRad / 2,
							this.wheelD, 48)

						// 加载材质 #AB1014
						const carMaterial = new THREE.MeshPhysicalMaterial({
							color: '#3C6DA8',
							transparent: true,
							metalness: 1.0,
							roughness: 0.7,
						})
						const wheelMaterial = new THREE.MeshPhysicalMaterial({
							color: '#222222',
							transparent: true,
							metalness: 0.0,
							roughness: 0.0,
						})
						// 轮毂材质
						const hubMaterial = new THREE.MeshPhysicalMaterial({
							color: '#ffffff',
							transparent: true,
							metalness: 1.0,
							roughness: 0.78,
						})
						const headMaterial = new THREE.MeshPhysicalMaterial({
							color: '#3C6DA8',
							transparent: true,
							// side: THREE.DoubleSide,
							// map: texture,
							metalness: 1.0,
							roughness: 0.7,
							clearcoat: 1.0, // 物体表面清漆层或者说透明涂层的厚度
							clearcoatRoughness: 1.0, // 透明涂层表面的粗糙度
						})
						const head_rt_Material = new THREE.MeshLambertMaterial({
							transparent: true,
							side: THREE.DoubleSide,
							map: this.textureLoader.load('./img/pic_rt_door.png', map => {}),
						})
						const head_lt_Material = new THREE.MeshLambertMaterial({
							transparent: true,
							side: THREE.DoubleSide,
							map: this.textureLoader.load('./img/pic_lt_door.png', map => {}),
						})
						const head_ft_Material = new THREE.MeshLambertMaterial({
							transparent: true,
							side: THREE.DoubleSide,
							map: this.textureLoader.load('./img/pic_head.png', map => {}),
						})

						// 创建车辆的几个部分
						const car = new THREE.Mesh(carGeometry, carMaterial)
						const wheel1 = new THREE.Mesh(wheelGeometry, wheelMaterial)
						const wheel2 = wheel1.clone()
						const wheel3 = wheel1.clone()
						const wheel4 = wheel1.clone()
						const wheel5 = wheel1.clone()
						const wheel6 = wheel1.clone()
						const hub1 = new THREE.Mesh(hubGeometry, hubMaterial)
						const hub2 = hub1.clone()
						const hub3 = hub1.clone()
						const hub4 = hub1.clone()
						const hub5 = hub1.clone()
						const hub6 = hub1.clone()
						// const head = new THREE.Mesh(headGeometry, [head_rt_Material, head_lt_Material, headMaterial,
						// 	headMaterial, headMaterial, headMaterial
						// ])
						const head = new THREE.Mesh(headGeometry, headMaterial)

						const wheelOst = 0.3 // 轮毂偏移量
						// 设置轮子的位置
						wheel1.position.set(this.wheelD / 2 + wheelOst, 0, this.wheelRad * 2)
						wheel2.position.set(this.truckX - this.wheelD / 2 - wheelOst, 0, this.wheelRad * 2)
						wheel3.position.set(this.wheelD / 2 + wheelOst, 0, this.truckZ - this.wheelRad * 2)
						wheel4.position.set(this.truckX - this.wheelD / 2 - wheelOst, 0, this.truckZ - this.wheelRad * 2)
						wheel5.position.set(this.wheelD / 2 + wheelOst, 0, -(this.headZ - this.wheelRad * 2))
						wheel6.position.set(this.truckX - this.wheelD / 2 - wheelOst, 0,
							-(this.headZ - this.wheelRad * 2))
						hub1.position.set(this.wheelD / 2, 0, this.wheelRad * 2)
						hub2.position.set(this.truckX - this.wheelD / 2, 0, this.wheelRad * 2)
						hub3.position.set(this.wheelD / 2, 0, this.truckZ - this.wheelRad * 2)
						hub4.position.set(this.truckX - this.wheelD / 2, 0, this.truckZ - this.wheelRad * 2)
						hub5.position.set(this.wheelD / 2, 0, -(this.headZ - this.wheelRad * 2))
						hub6.position.set(this.truckX - this.wheelD / 2, 0, -(this.headZ - this.wheelRad * 2))
						// 设置车身的位置
						car.position.set(this.truckX / 2, this.truckY, this.truckZ / 2)
						// 设置车头位置
						head.position.set(this.headX / 2, this.headY / 2 + this.truckY / 2, -this.headZ / 2 - 0)

						// 旋转轮子
						rotateXZ90(wheel1, wheel2, wheel3, wheel4, wheel5, wheel6, hub1, hub2, hub3, hub4, hub5, hub6, )

						this.t_group.add(wheel1, wheel2, wheel3, wheel4, wheel5, wheel6)
						this.t_group.add(hub1, hub2, hub3, hub4, hub5, hub6)
						this.t_group.add(car, head)
						// 拼装车辆,并添加到场景
						this.tg_group.add(this.t_group)
						this.scene.add(this.tg_group)

					},

					// 创建货物(初始版本)
					createMesh1() {

						// 计算x轴方向数量
						let num1 = 2
						// 计算y轴方向数量
						let num2 = 2
						// 计算z轴方向数量
						let num3 = 4

						const goodsX = 100
						const goodsY = 50
						const goodsZ = 75

						let meshIndex = 1 // 模型计数
						for (let i = 0; i < num1; i++) {
							for (let j = 0; j < num2; j++) {
								for (let k = 0; k < num3; k++) {
									//创建一个长方体几何对象Geometry
									const geometry = new THREE.BoxGeometry(goodsX, goodsY, goodsZ);
									// 材质对象 MeshBasicMaterial MeshLambertMaterial
									const material = new THREE.MeshLambertMaterial({
										color: '#AE875F', // 设置材质颜色
										transparent: false, //开启透明
										opacity: 1.0, //设置透明度
									});
									// 两个参数分别为几何体geometry、材质material
									const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
									// 设置网格模型在三维空间中的位置坐标，默认是坐标原点
									mesh.position.set(i * (goodsX + 10) + goodsX / 2 + 10, j * (goodsY + 1) +
										this.truckY * 3 / 2 + goodsY / 2, k * (goodsZ + 1) + goodsZ / 2 + 10)

									mesh.name = `货物${meshIndex}`
									mesh.userData = this.tpList[0]
									// 货物模型添加到货物分组
									// this.g_group.add(mesh)
									// 记录生成的货物模型
									this.goodsMeshList.push(mesh)
									meshIndex++

									this.renderer.domElement.addEventListener('mousedown', event => {
										// 监听鼠标按下事件
										// this.onDomMouseDown(event)
									})

									// document.addEventListener('mousemove', event => {
									this.renderer.domElement.addEventListener('mousemove', event => {
										// 监听鼠标移动事件
										this.showHoverBox(event)
									})

								}
							}

						}

						// 拼装货物,并添加到场景
						this.tg_group.add(this.g_group)
						this.scene.add(this.tg_group)
					},

					// 创建货物(第二版)
					createMesh2() {
						// 计算x轴方向数量
						let num1 = 2
						// 计算z轴方向数量
						let num3 = 3
						// 计算y轴方向数量
						let num2 = Math.ceil(this.tpList.length / (num1 * num3))

						let meshIndex = 0 // 托盘索引
						for (let i = 0; i < num2; i++) {
							for (let j = 0; j < num3; j++) {
								for (let k = 0; k < num1; k++) {
									if (meshIndex >= this.tpList.length) break
									console.log('this.tpList[meshIndex] = ', this.tpList[meshIndex])
									const goodsX = this.tpList[meshIndex].width
									const goodsY = this.tpList[meshIndex].hight
									const goodsZ = this.tpList[meshIndex].length
									//创建一个长方体几何对象Geometry
									const geometry = new THREE.BoxGeometry(goodsX, goodsY, goodsZ)
									// 材质对象 MeshBasicMaterial MeshLambertMaterial
									const material = new THREE.MeshLambertMaterial({
										color: '#AE875F', // 设置材质颜色
										transparent: false, // 开启透明
										opacity: 1.0, // 设置透明度
									});
									// 两个参数分别为几何体geometry、材质material
									const mesh = new THREE.Mesh(geometry, material); // 网格模型对象Mesh
									// 设置网格模型在三维空间中的位置坐标，默认是坐标原点
									mesh.position.set(k * (goodsX + 10) + goodsX / 2 + 10, i * (goodsY + 1) +
										this.truckY * 3 / 2 + goodsY / 2, j * (goodsZ + 1) + goodsZ / 2 + 10)

									mesh.name = `货物${meshIndex + 1}`
									mesh.userData = this.tpList[meshIndex]
									// 货物模型添加到货物分组
									// this.g_group.add(mesh)
									// 记录生成的货物模型
									this.goodsMeshList.push(mesh)
									meshIndex++

									this.renderer.domElement.addEventListener('mousedown', event => {
										// 监听鼠标按下事件
										// this.onDomMouseDown(event)
									})

									// document.addEventListener('mousemove', event => {
									this.renderer.domElement.addEventListener('mousemove', event => {
										// 监听鼠标移动事件
										this.showHoverBox(event)
									})

								}
							}

						}

						// 拼装货物,并添加到场景
						this.tg_group.add(this.g_group)
						this.scene.add(this.tg_group)

					},

					// 创建货物(第三版)
					// createMesh() {

					// 	// 计算x轴方向数量
					// 	let num1 = 2
					// 	// 计算z轴方向数量
					// 	let num3 = 7
					// 	// 计算y轴方向数量
					// 	let num2 = Math.ceil(this.tpList.length / (num1 * num3))
					// 	console.log('num2 = ', num2);

					// 	let meshIndex = 0 // 托盘索引
					// 	for (let i = 0; i < num2; i++) {
					// 		for (let j = 0; j < num3; j++) {
					// 			for (let k = 0; k < num1; k++) {
					// 				if (meshIndex >= this.tpList.length) break
					// 				console.log('this.tpList[meshIndex] = ', this.tpList[meshIndex])
					// 				const goodsX = this.tpList[meshIndex].width
					// 				const goodsY = this.tpList[meshIndex].hight
					// 				const goodsZ = this.tpList[meshIndex].length
					// 				//创建一个长方体几何对象Geometry
					// 				const geometry = new THREE.BoxGeometry(goodsX, goodsY, goodsZ)
					// 				// 材质对象 MeshBasicMaterial MeshLambertMaterial
					// 				const material = new THREE.MeshLambertMaterial({
					// 					color: '#AE875F', // 设置材质颜色
					// 					transparent: false, // 开启透明
					// 					opacity: 1.0, // 设置透明度
					// 				});
					// 				// 两个参数分别为几何体geometry、材质material
					// 				const mesh = new THREE.Mesh(geometry, material); // 网格模型对象Mesh
					// 				// 设置网格模型在三维空间中的位置坐标，默认是坐标原点
					// 				// mesh.position.set(k * (goodsX + 10) + goodsX / 2 + 10, i * (goodsY + 1) +
					// 				// 	this.truckY * 3 / 2 + goodsY / 2, j * (goodsZ + 1) + goodsZ / 2 + 10)

					// 				let mX = 0
					// 				let mY = 0
					// 				let mZ = 0

					// 				if (i == 0) {
					// 					mY = this.truckY * 3 / 2 + goodsY / 2
					// 				} else {
					// 					mY = this.goodsMeshList[meshIndex - 1].position.y +
					// 						this.tpList[meshIndex - 1]['hight'] / 2 + goodsY / 2
					// 				}

					// 				// 计算y坐标
					// 				// let underIndex = meshIndex / (num1 * num3) + meshIndex % (num1 * num3)
					// 				// mY = this.goodsMeshList[meshIndex - underIndex].position.y +
					// 				// 	this.tpList[meshIndex - 1]['hight'] / 2 + goodsY / 2

					// 				if (j == 0 || meshIndex < 2) {
					// 					mZ = goodsZ / 2 + 10
					// 				} else {
					// 					mZ = this.goodsMeshList[meshIndex - 2].position.z +
					// 						this.tpList[meshIndex - 2]['length'] / 2 + goodsZ / 2 + 4
					// 				}
					// 				if (k == 0) {
					// 					mX = goodsX / 2 + 20
					// 				} else {
					// 					mX = this.goodsMeshList[meshIndex - 1].position.x +
					// 						this.tpList[meshIndex - 1]['width'] / 2 + goodsX / 2 + 4
					// 				}

					// 				mesh.position.set(mX, mY, mZ)

					// 				mesh.name = `货物${meshIndex + 1}`
					// 				mesh.userData = this.tpList[meshIndex]
					// 				// 货物模型添加到货物分组
					// 				// this.g_group.add(mesh)
					// 				// 记录生成的货物模型
					// 				this.goodsMeshList.push(mesh)
					// 				meshIndex++

					// 				this.renderer.domElement.addEventListener('mousedown', event => {
					// 					// 监听鼠标按下事件
					// 					// this.onDomMouseDown(event)
					// 				})

					// 				// document.addEventListener('mousemove', event => {
					// 				this.renderer.domElement.addEventListener('mousemove', event => {
					// 					// 监听鼠标移动事件
					// 					this.showHoverBox(event)
					// 				})

					// 			}
					// 		}

					// 	}

					// 	// 拼装货物,并添加到场景
					// 	this.tg_group.add(this.g_group)
					// 	this.scene.add(this.tg_group)

					// },

					// 创建货物(第四版)
					createMesh() {

						// 遍历货物 计算最大层数
						let maxL = 0
						this.tpList.map((item, index) => {
							if (item.layers > maxL) {
								maxL = item.layers
							}
						})
						console.log('maxL = ', maxL);

						// 根据层数 确定每层的货物数量
						let layerArr = []
						for (let a = 1; a <= maxL; a++) {
							layerArr[a - 1] = this.tpList.filter(item => item.layers == a).length
						}
						console.log('layerArr = ', layerArr);

						let meshIndex = 0 // 托盘索引
						// 遍历生成的层数数组(记录每层的货物数量)
						for (let b = 0; b < layerArr.length; b++) {
							// if (b == 1) break
							for (let c = 0; c < layerArr[b]; c++) {
								// console.log('c = ', c);

								const goodsX = this.tpList[meshIndex].width
								const goodsY = this.tpList[meshIndex].hight
								const goodsZ = this.tpList[meshIndex].length

								//创建一个长方体几何对象Geometry
								const geometry = new THREE.BoxGeometry(goodsX, goodsY, goodsZ)
								// 材质对象 MeshBasicMaterial MeshLambertMaterial
								const material = new THREE.MeshLambertMaterial({
									color: '#AE875F', // 设置材质颜色
									transparent: false, // 开启透明
									opacity: 1.0, // 设置透明度
								})
								// 两个参数分别为几何体geometry、材质material
								const mesh = new THREE.Mesh(geometry, material) // 网格模型对象Mesh

								let mX = 0
								let mY = 0
								let mZ = 0

								if (b == 0) {
									mY = this.truckY * 3 / 2 + goodsY / 2
								} else {
									try {
										mY = this.goodsMeshList[meshIndex - layerArr[b]].position.y +
											this.tpList[meshIndex - layerArr[b]]['hight'] / 2 + goodsY / 2
									} catch (e) {
										mY = this.goodsMeshList[meshIndex - layerArr[b - 1]].position.y +
											this.tpList[meshIndex - layerArr[b - 1]]['hight'] / 2 + goodsY / 2
									}

								}

								if (c == 0 || meshIndex % 16 < 2) {
									mZ = goodsZ / 2 + 10
								} else {
									mZ = this.goodsMeshList[meshIndex - 2].position.z +
										this.tpList[meshIndex - 2]['length'] / 2 + goodsZ / 2 + 4
								}

								if (c % 2 == 0) {
									mX = goodsX / 2 + 2
								} else {
									let offsetX = goodsX > 101 ? 34 : 78
									mX = this.goodsMeshList[meshIndex - 1].position.x +
										this.tpList[meshIndex - 1]['width'] / 2 + goodsX / 2 + offsetX
								}

								mesh.position.set(mX, mY, mZ)

								mesh.name = `货物${meshIndex + 1}`
								mesh.userData = this.tpList[meshIndex]
								// 货物模型添加到货物分组
								// this.g_group.add(mesh)
								// 记录生成的货物模型
								this.goodsMeshList.push(mesh)
								meshIndex++

								this.renderer.domElement.addEventListener('mousemove', event => {
									// 监听鼠标移动事件
									this.showHoverBox(event)
								})

							}
						}

						// console.log('this.goodsMeshList = ', this.goodsMeshList);

						// 拼装货物,并添加到场景
						this.tg_group.add(this.g_group)
						this.scene.add(this.tg_group)

					},

					// 渲染循环
					animate() {
						// console.log('this.tg_group.rotation = ', this.tg_group.rotation);
						if (this.debug.is_rotate) {
							this.tg_group.rotation.y += 0.003
						}

						// this.renderer.render(this.scene, this.camera)
						this.composer.render() // 按照标准 执行效果生成器的渲染不需要再执行渲染器的渲染
						requestAnimationFrame(this.animate)
					},

					// 创建标注
					createTag() {
						const div = document.getElementById('tag')
						// HTML元素转化为threejs的CSS2模型对象
						const tag = new CSS2DObject(div)
						tag.position.set(0, 400, 0);
						this.scene.add(tag);

						this.css2Renderer = new CSS2DRenderer()
						this.css2Renderer.setSize(innerWidth, innerHeight)
						document.body.appendChild(this.css2Renderer.domElement)
						document.getElementById('webgl').appendChild(this.css2Renderer.domElement)
						this.css2Renderer.render(this.scene, this.camera)

						this.css2Renderer.domElement.style.position = 'absolute'
						this.css2Renderer.domElement.style.top = '0px'

						this.css2Renderer.domElement.style.pointerEvents = 'none'
						// this.renderer.domElement.style.zIndex = -1
						// css2Renderer.domElement.style.zIndex = 1

					},

					// GLTFLoader
					createGLTFLoader() {
						// this.loader = new GLTFLoader()

						// this.loader.load('./gltf/truck_head.glb', gltf => {
						// 	console.log('控制台查看加载gltf文件返回的对象结构', gltf);
						// 	console.log('gltf对象场景属性', gltf.scene);

						// 	// gltf.scene.children[0].scale.set(1, 1, 1)
						// 	// gltf.scene.children[0].position.set(200, 200, 200)
						// 	// gltf.scene.children[1].scale.set(1, 1, 1)
						// 	// gltf.scene.children[1].position.set(200, 200, 200)
						// 	// 返回的场景对象gltf.scene插入到threejs场景中
						// 	this.scene.add(gltf.scene)
						// })
					},

					// 后期处理
					postProcessing() {
						// 创建后处理对象EffectComposer，WebGL渲染器作为参数
						this.composer = new EffectComposer(this.renderer)
						// 创建一个渲染器通道，场景和相机作为参数
						const renderPass = new RenderPass(this.scene, this.camera)
						// 为效果生成器设置renderPass通道
						this.composer.addPass(renderPass)
						// OutlinePass第一个参数v2的尺寸和canvas画布保持一致
						const v2 = new THREE.Vector2(innerWidth, innerHeight)
						this.outlinePass = new OutlinePass(v2, this.scene, this.camera)
						this.outlinePass.visibleEdgeColor.set('#ffffff')
						// this.outlinePass.edgeThickness = 1 // 高光厚度
						// 为特效生成器设置OutlinePass描边通道
						this.composer.addPass(this.outlinePass)
						// 高光描边加抗锯齿
						// let FXAAShaderPass = new THREE.ShaderPass(THREE.FXAAShader)
						// FXAAShaderPass.uniforms['resolution'].value.set(1 / width, 1 / height)
						// FXAAShaderPass.renderToScreen = true
						// this.composer.addPass(FXAAShaderPass)

					},

					// 重置页面
					reset() {
						// location.reload()
						// 移除倒计时
						this.timeOutList.map(item => {
							clearTimeout(item)
						})
						// 清空原有模型
						this.goodsMeshList = []
						this.g_group.children = []
						// 重新创建模型
						this.createMesh()

					},

					// 导出效果图
					importImg() {
						// let src = this.renderer.domElement.toDataURL();
						// let a = document.createElement("a") // 生成一个a元素
						// let event = new MouseEvent("click") // 创建一个单击事件
						// a.download = "装载效果图" // 设置图片名称
						// a.href = src // 将生成的URL设置为a.href属性
						// a.dispatchEvent(event) // 触发a的单击事件 将图片下载下来

						this.renderer.render(this.scene, this.camera) // 执行渲染操作
						// 创建一个超链接元素，用来下载保存数据的文件
						var link = document.createElement('a');
						// 通过超链接herf属性，设置要保存到文件中的数据
						var canvas = this.renderer.domElement; //获取canvas对象
						link.href = canvas.toDataURL("image/png");
						link.download = '装载效果图.png'; //下载文件名
						link.click(); //js代码触发超链接元素a的鼠标点击事件，开始下载文件到本地

					},

					// 点击:触发开始装车动画
					onStartLoad() {
						this.reset()
						this.loadAnimation()
					},

					// 执行货物装载动画
					loadAnimation() {
						if (this.goodsMeshList) {
							this.goodsMeshList.map((item, index) => {
								// console.log('遍历模型准备加载动画...', item);
								let originalY = item.position.y // 记录原始的y坐标
								this.meshAnimation(item, index, originalY)
							})
						}
					},

					// 货物模型装载动画
					meshAnimation(item, index, originalY) {
						item.position.y += innerHeight * 3 / 3
						// 货物模型添加到货物分组
						this.g_group.add(item)
						const tid = setTimeout(() => {
							setInterval(() => {
								if (item.position.y >= originalY) {
									item.position.y -= 2
								}
							}, 2)
						}, index * 1200)
						// 收集倒计时id,重置时先取消这些倒计时器
						this.timeOutList.push(tid)
					},

					// 模型边界线
					createOutline() {
						const geometry = new THREE.BoxGeometry(this.truckX, 330, this.truckZ);
						const material = new THREE.MeshLambertMaterial({
							color: 0xff0000,
							transparent: true,
							opacity: 0.2,
						});
						const mesh = new THREE.Mesh(geometry, material);

						// 长方体作为EdgesGeometry参数创建一个新的几何体
						const edges = new THREE.EdgesGeometry(geometry);
						const edgesMaterial = new THREE.LineBasicMaterial({
							color: 0x00ffff,
						})
						const line = new THREE.LineSegments(edges, edgesMaterial);
						mesh.add(line);

						mesh.translateZ(462)
						mesh.translateX(140)
						mesh.translateY(195)

						this.scene.add(mesh)
					},

				}
			})
		</script>

	</body>
</html>